package com.jfire.json.serializer;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.jfire.baseutil.collection.ObjectCollect;
import com.jfire.baseutil.collection.StringCache;
import com.jfire.json.JsonObject;
import com.jfire.json.field.JsonField;
import com.jfire.json.util.JsonConfig;
import com.jfire.json.util.JsonSerializer;

public class MapSerializer implements JsonSerializer
{
    @Override
    public Object transToJsonvalue(Object src, ObjectCollect collect)
    {
        JsonObject jsonObject = new JsonObject();
        for (Entry<?, ?> each : ((Map<?, ?>) src).entrySet())
        {
            jsonObject.put((String) JsonConfig.getSerializer(each.getKey().getClass()).transToJsonvalue(each.getKey(), collect), JsonConfig.getSerializer(each.getValue().getClass()).transToJsonvalue(each.getValue(), collect));
        }
        return jsonObject;
    }
    
    @Override
    public void setJsonFields(JsonField[] jsonFields)
    {
        
    }
    
    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public void writeToString(StringCache cache, Object value, ObjectCollect collect)
    {
        Set<Entry> set = ((Map) value).entrySet();
        cache.append('{', set.size() * 2 + 1);
        for (Entry<?, ?> each : set)
        {
            if (each.getKey() != null && each.getValue() != null)
            {
                JsonConfig.getSerializer(each.getKey().getClass()).writeToString(cache, each.getKey(), collect);
                cache.append(':');
                JsonConfig.getSerializer(each.getValue().getClass()).writeToString(cache, each.getValue(), collect);
                cache.append(',');
            }
        }
        if (cache.isCommaLast())
        {
            cache.deleteLast();
        }
        cache.append('}');
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    public Object toBean(Object json, Type type)
    {
        Map map = null;
        if (HashMap.class.isAssignableFrom((Class<?>) ((ParameterizedType) type).getRawType()) || Map.class.isAssignableFrom((Class<?>) ((ParameterizedType) type).getRawType()))
        {
            map = new HashMap<>();
        }
        Type keyType = ((ParameterizedType) type).getActualTypeArguments()[0];
        Type valueType = ((ParameterizedType) type).getActualTypeArguments()[1];
        JsonSerializer keySerializer = null;
        JsonSerializer valueSerializer = null;
        if (keyType instanceof ParameterizedType)
        {
            keySerializer = JsonConfig.getSerializer((Class<?>) ((ParameterizedType) keyType).getRawType());
        }
        else
        {
            keySerializer = JsonConfig.getSerializer((Class<?>) keyType);
        }
        if (valueType instanceof ParameterizedType)
        {
            valueSerializer = JsonConfig.getSerializer((Class<?>) ((ParameterizedType) valueType).getRawType());
        }
        else
        {
            valueSerializer = JsonConfig.getSerializer((Class<?>) valueType);
        }
        for (Entry<String, Object> entry : ((JsonObject) json).entrySet())
        {
            map.put(keySerializer.toBean(entry.getKey(), keyType), valueSerializer.toBean(entry.getValue(), valueType));
        }
        return map;
    }
    
}
